package com.yzh.openai.domain.auth.service;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.yzh.openai.domain.auth.model.entity.UserEntity;
import com.yzh.openai.domain.auth.repository.IUserRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import com.auth0.jwt.algorithms.Algorithm;
import com.yzh.openai.domain.auth.model.entity.AuthStateEntity;
import com.yzh.openai.domain.auth.model.valobj.AuthTypeVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


@Slf4j
public abstract class AbstractAuthService implements IAuthService{
    private static final String defaultBase64EncodedSecretKey = "y!~#@#z%$%^&h";
    private final String base64EncodedSecretKey = Base64.encodeBase64String(defaultBase64EncodedSecretKey.getBytes());
    private final Algorithm algorithm = Algorithm.HMAC256(Base64.decodeBase64(base64EncodedSecretKey.getBytes()));
    @Resource
    protected IUserRepository userRepository;
    @Override
    public AuthStateEntity doLogin(String code) {
        //0.管理员登录输入admin访问码即可
        if (code.equals("admin") || code.equals("ADMIN")){
            AuthStateEntity authStateEntity = new AuthStateEntity();
            authStateEntity.setCode(AuthTypeVO.A0000.getCode());
            authStateEntity.setOpenId("admin");

            Map<String, Object> chaim = new HashMap<>();
            chaim.put("openId", "admin");
            String token = encode("admin", 7 * 24 * 60 * 60 * 1000, chaim);
            authStateEntity.setToken(token);
            return authStateEntity;
        }
        
        
        //1.如果不是4位有效数组字符串，返回验证码无效
        if (!code.matches("\\d{4,6}")) {
            log.info("鉴权，用户输入验证码无效{}", code);
            return AuthStateEntity.builder()
                    .code(AuthTypeVO.A0002.getCode())
                    .info(AuthTypeVO.A0002.getInfo())
                    .build();
        }
        //2.校验判断，不成功直接返回
        AuthStateEntity authStateEntity = this.checkCode(code);
        if (!authStateEntity.getCode().equals(AuthTypeVO.A0000.getCode())) {
            return authStateEntity;
        }
        
        //3.获取Token并返回
        Map<String, Object> chaim = new HashMap<>();
        chaim.put("openId", authStateEntity.getOpenId());
        String token = encode(authStateEntity.getOpenId(), 7 * 24 * 60 * 60 * 1000, chaim);
        authStateEntity.setToken(token);
        
        return authStateEntity;
    }

    @Override
    public abstract UserEntity queryUserInfo(String token);


    public abstract AuthStateEntity checkCode(String code);

    /**
     * 生成JWT
     * @param issuer     签发人
     * @param ttlMillis  过期时间
     * @param claims     可以存储非隐私信息
     * @return
     */
    protected String encode(String issuer, long ttlMillis, Map<String, Object> claims) {
        if (claims == null) {
            claims = new HashMap<>();
        }
        
        JwtBuilder jwtBuilder = Jwts.builder()
                .setClaims(claims)  //荷载
                .setId(UUID.randomUUID().toString())   //唯一标识
                .setIssuer(issuer)  //签发人
                .setIssuedAt(new Date(System.currentTimeMillis()))  //签发时间
                .signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey);

        if (ttlMillis >= 0) {
            Date expTime = new Date(System.currentTimeMillis() + ttlMillis);
            jwtBuilder.setExpiration(expTime);  //过期时间
        }
        return jwtBuilder.compact();
    }

    /**
     * 解密JWT，拿到荷载部分
     * @param jwtToken
     * @return
     */
    protected Claims decode(String jwtToken) {
        return Jwts.parser()
                .setSigningKey(base64EncodedSecretKey)  //设置签名秘钥
                .parseClaimsJws(jwtToken)   //设置要解析的JWT TOKEN
                .getBody();
    }

    /**
     * 判断jwtToken是否合法
     * @param jwtToken
     * @return
     */
    protected boolean isVerify(String jwtToken) {
        try {
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(jwtToken);
            return true;
        } catch (Exception e) {
            log.error("JWT isVerify Err", e);
            return false;
        }
    }
}
